
#include "rviz_custom_plugins/widgets/file_transfer_dialog.h"
#include "rviz_custom_plugins/utils/net_util.h"
#include <chrono>
#include <QMessageBox>
#include <QDateTime>
#include <QTimer>
#include "rviz_common/logging.hpp"
#include <string>


using rviz_custom_plugins::utils::getLocalIPv4;
using namespace std::chrono_literals;


namespace rviz_custom_plugins
{


namespace widgets 
{


FileTransferDialog::FileTransferDialog(QWidget *parent): QDialog(parent), 
    ui(new Ui::fileTransferDialog()), context(nullptr)
{
    ui->setupUi(this);
    setWindowTitle("文件传输对话框");
}


void FileTransferDialog::initialize(DisplayContext * context) 
{
    this->context = context;
    node = this->context->getRosNodeAbstraction().lock()->get_raw_node();
    fileTransferClient = node->create_client<FileTransCmd>("file_trans_cmd");
    fileTransferQueryClient = node->create_client<FileTransStatus>("file_trans_status");
    connect(ui->transferBtn, &QPushButton::clicked, this, &FileTransferDialog::startTransfer);
}


void FileTransferDialog::setTransMode(int transMode)
{
    this->transMode = transMode;
    QString transModeStr = (this->transMode == 1 ? "上传": "下载");
    ui->transModeLabel->setText("传输模式：" + transModeStr);
}


void FileTransferDialog::setGroundPath(QString groundPath)
{
    this->groundPath = groundPath;
    ui->groundPathLb->setText("地面站端路径:" + this->groundPath);
}


void FileTransferDialog::setAirPath(QString airPath)
{
    this->airPath = airPath;
    ui->airPathLb->setText("无人机端路径:" + this->airPath);
}


void FileTransferDialog::startTransfer()
{

    if(transHash.contains(this->groundPath)){
        QMessageBox::information(this, "提示", "文件正在传输中");
        return;
    }

    // qint64 currentTs = QDateTime::currentSecsSinceEpoch();
    transHash.insert(this->groundPath, 0);

    auto request = std::make_shared<FileTransCmd::Request>();
    request->trans_mode = this->transMode;
    std::string ipAddr = getLocalIPv4().toStdString();
    RCLCPP_INFO(rclcpp::get_logger("rclcpp"), ipAddr.c_str());
    request->ground_host = ipAddr;
    request->ground_user = "visbot";
    request->auth_mode = 0;
    request->ground_ssh_key = "visbot";
    request->ground_path = this->groundPath.toStdString();
    request->air_path = this->airPath.toStdString();
    request->md5 = "";

    bool isServiceValid = fileTransferClient->wait_for_service(0.5s);
    if(!isServiceValid) {
        transHash.remove(this->groundPath);
        QMessageBox::warning(this, "警告", "传输服务不可用");
        RCLCPP_WARN(rclcpp::get_logger("rclcpp"), "transfer service not available...");
        return;
    }

    RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "transfer service is available...");


    fileTransferClient->async_send_request(
        request,
        [this, transKey = this->groundPath](rclcpp::Client<FileTransCmd>::SharedFuture future)
        {
            auto response = future.get();
            if(response->result != 512) 
            {
                transHash.remove(transKey);
                QString errorMsg = QString::fromStdString(response->message);
                QMessageBox::warning(this, "警告", "传输请求失败：" + errorMsg);
                RCLCPP_WARN(rclcpp::get_logger("rclcpp"), response->message.c_str());
                return;
            }
            transHash.insert(transKey, response->trans_id);
            RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "transfer service response succeed");
            transferQuery(transKey);
        }
    );

}


void FileTransferDialog::transferQuery(QString transKey)
{
    auto request = std::make_shared<FileTransStatus::Request>();
    request->trans_id = transHash[transKey];

    bool isServiceValid = fileTransferQueryClient->wait_for_service(0.5s);
    if(!isServiceValid) {
        transHash.remove(transKey);
        QMessageBox::warning(this, "提示", "传输查询服务不可用");
        RCLCPP_WARN(rclcpp::get_logger("rclcpp"), "query service not available...");
        return;
    }

    fileTransferQueryClient->async_send_request(
        request,
        [this, transKey = transKey](rclcpp::Client<FileTransStatus>::SharedFuture future)
        {
            auto response = future.get();

            std::ostringstream sstm;
            sstm << " transfer status service response succeed, msg:" << response->message;
            sstm << " status:" << static_cast<unsigned int>(response->status);
            sstm << " progress:" << response->progress;
            std::string log = sstm.str();
            RVIZ_COMMON_LOG_INFO(log.c_str());

            if(response->result != 512) 
            {
                transHash.remove(transKey);
                QString errorMsg = QString::fromStdString(response->message);
                QMessageBox::warning(this, "提示", "传输进度请求失败：" + errorMsg);
                RCLCPP_WARN(rclcpp::get_logger("rclcpp"), "transfer query failed");
                return;
            }
            // pending
            if (response->status == 0)
            {
                QTimer::singleShot(200, this, [this, transKey = transKey](){
                    transferQuery(transKey);
                });
            }
            // running
            if(response->status == 1) 
            {
                ui->progressBar->setValue(response->progress);
                QTimer::singleShot(200, this, [this, transKey = transKey](){
                    transferQuery(transKey);
                });
            } 
            // completed
            else if(response->status == 2)
            {
                ui->progressBar->setValue(response->progress);
                transHash.remove(transKey);
                QMessageBox::information(this, "提示", "文件传输完成");
                this->done(QDialog::Accepted);
            }
            // failed
            else if(response->status == 3)
            {
                transHash.remove(transKey);
                QString errorMsg = QString::fromStdString(response->message);
                QMessageBox::critical(this, "错误", "文件传输失败:" + errorMsg);
            }
        }
    );
}


}

}